#include "fan.hpp"

#include "qbe/src/ecs/app.hpp"

#include "qbe/src/ecs/query.hpp"

#include "qbe/src/axis/axis.hpp"
#include "qbe/src/input/input.hpp"
#include "qbe/src/select/select.hpp"
#include "qbe/src/state/state.hpp"
#include "qbe/src/undoRedo/undoRedo.hpp"
#include "qbe/src/utils/utils.hpp"

#include "qbe/src/layout/layout.hpp"

#include "qlib/all.h"

#include "../components.hpp"
#include "../events.hpp"

#include <QMessageBox>

#include "../../operationLayer/operationLayer.h"

#include <QMessageBox>
#include <QRegularExpression>
#include <QRegularExpressionValidator>

#include <QAction>

#include <QWidget>

namespace qbe::draw::fan {

// 移除标记
void clear_tag(ecs::Query query) {
  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 遍历Tag并移除
  auto view_cache_add = reg.view<FanCacheAddTag>();
  view_cache_add.each([&reg](entt::entity e) { reg.remove<FanCacheAddTag>(e); });

  auto view_cache_update = reg.view<FanCacheUpdateTag>();
  view_cache_update.each([&reg](entt::entity e) { reg.remove<FanCacheUpdateTag>(e); });

  auto view_cache_delete = reg.view<FanCacheDeleteTag>();
  view_cache_delete.each([&reg](entt::entity e) { reg.remove<FanCacheDeleteTag>(e); });

  auto view_add = reg.view<FanAddTag>();
  view_add.each([&reg](entt::entity e) { reg.remove<FanAddTag>(e); });
}

// 添加临时对象
void add_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models,
                   ecs::Query query) {
  auto ptr = reg.get<qlib::Fan::s_ptr>(entity);
  auto polygon = ptr->to_polygon();

  models.mesh = render::PolyLineMesh(polygon->points, true);

  auto& ol = query.get_resource<ol::Models>();
  ol.clearAllSelect();

  event_writer.send({Code::FanCacheAdd});

  if (models.complete_entity != entt::null) {
    reg.remove<select::SelectTag>(models.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    models.complete_entity = entt::null;
  }
}

// 更新临时对象
void update_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models) {
  auto ptr = reg.get<qlib::Fan::s_ptr>(entity);
  auto polygon = ptr->to_polygon();

  models.mesh = render::PolyLineMesh(polygon->points, true);

  event_writer.send({Code::FanCacheUpdate});
}

// 删除临时对象
void delete_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models) {
  reg.destroy(entity);

  event_writer.send({Code::FanCacheDelete});
}

// 添加对象
void add_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity,
             undoRedoT::UndoRedoModule& undoRedoModuel, qlib::Cell::s_ptr cell, Models& models, ecs::Query query, state::State& state) {
  auto ptr = reg.get<qlib::Fan::s_ptr>(entity);
  bool have_layer = state.getCurrentLayer(ptr->layer);

  if (have_layer) {
    auto e = cmd.add(ptr);
    models.complete_entity = e;

    undoRedoModuel.start(cell);
    undoRedoModuel.add(e);
    undoRedoModuel.end();

    reg.emplace<FanAddTag>(e);
    event_writer.send({Code::FanAdd});

    reg.emplace_or_replace<select::SelectTag>(e);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});
  }

  delete_cache_obj(reg, event_writer, cmd, entity, models);
}

// 退出绘制模式时回调
void exit_callback(ecs::Query query, state::AllModeType new_mode) {
  // 获取参数
  auto& param = query.get_resource<Models>();

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& models = query.get_resource<Models>();

  // 获取事件写入器
  auto event_writer = query.get_event_writer<draw::Event>();

  // 删除临时对象
  if (param.entity != entt::null) {
    delete_cache_obj(reg, event_writer, layout_cmd, param.entity, models);
  }

  if (param.complete_entity != entt::null && !state::isModeType<state::EditingModeType>(new_mode)) {
    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  // 重置参数
  param.reset();

  auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
  absorbModule.close_diagonal_start();
}

void exit(ecs::Query query) {
  // 获取参数
  auto& param = query.get_resource<Models>();
  auto& state = query.get_resource<state::State>();

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& models = query.get_resource<Models>();

  // 获取事件写入器
  auto event_writer = query.get_event_writer<draw::Event>();

  // 删除临时对象
  if (param.entity != entt::null) {
    delete_cache_obj(reg, event_writer, layout_cmd, param.entity, models);
  }

  if (param.complete_entity != entt::null) {
    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  if (param.entity == entt::null) {
    state.exit();
  }

  // 重置参数
  param.reset();
  auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
  absorbModule.close_diagonal_start();
}

void init(ecs::Commands command, ecs::Query query) {
  Models param;
  command.insert_resource(param);

  auto& state = query.get_resource<state::State>();
  state.addExitCall(state::DrawingModeType::Fan, exit_callback);
}

// 帧开始，模式转换
void stateTransformBegin(Models& param, input::HandleBundle* handle) {
  // 执行操作的状态完成则回退，不存在维持情况
  assert(param.state == State::None);

  // 按下ecs必然回退
  if (handle->keyReleased(vsg::KEY_Escape)) {
    param.state = State::Cancel;
    return;
  }

  // 左键按下必然响应
  if (handle->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) {
    if (param.entity == entt::null)
      param.state = State::Create;
    else if (param.have_r == false)
      param.state = State::Create;
    else if (param.have_r == true)
      param.state = State::Complete;
    return;
  }

  // 最低优先级，移动
  if (param.entity != entt::null && handle->mouse_move) {
    param.state = State::Update;
    param.is_moveing = true;
    return;
  }
}

// 帧尾-退出模式
void stateTransformEnd(State& state) {
  // 操作模式执行完就应该回退
  if (state == State::Create || state == State::Update || state == State::Complete || state == State::Cancel) {
    state = State::None;
  }
}

qlib::Vec2d getNowPoint(ecs::Query query, qlib::Vec2d prePoint) {
  {
    auto& axisModule = query.get_resource<axis::Axis>();
    qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.set_diagonal_start(prePoint);

    return pos;
  }

  auto& state = query.get_resource<state::State>();

  if (!state.isAdsorption()) {
    if (!state.isAngleTheAdsorption()) {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return pos;
    } else {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  } else {
    if (!state.isAngleTheAdsorption()) {
      return utils::getAdsorbedPoint(query);
    } else {
      qlib::Vec2d pos = utils::getAdsorbedPoint(query);
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  }
}

void update(ecs::Query query) {
  // 判断编辑模式为绘制
  auto& state = query.get_resource<state::State>();

  if (state.getDrawingMode() != state::DrawingModeType::Fan)
    return;

  auto& select_models = query.get_resource<select::OverallModel>();
  // select_models.mouse_press = false;
  // select_models.mouse_release = false;

  {
    auto& ol = query.get_resource<ol::Models>();

    uint32_t currentLayer = 0;
    if (state.getCurrentLayer(currentLayer)) {
      bool currentLayerHide = ol.currentLayerIsHide(currentLayer);
      if (currentLayerHide) {
        exit(query);
        return;
      }
    }
  }

  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取输入 坐标系 撤销恢复
  auto& handModule = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axisModule = query.get_resource<axis::Axis>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();

  // 获取参数
  auto& param = query.get_resource<Models>();
  auto& entity = param.entity;

  // 获取事件写入器
  auto event_writer = query.get_event_writer<draw::Event>();

  stateTransformBegin(param, handModule);

  {
    uint32_t layer;
    if (!state.getCurrentLayer(layer)) {
      QMessageBox::information(nullptr, QObject::tr("error"), QObject::tr("No layer selected, unable to draw"));
      exit(query);
    }
  }

  // 获取当前鼠标点
  layout::Vec2d pos = {axisModule.real_x, axisModule.real_y};

  if (param.state == State::Cancel) {
    exit(query);
  }

  // 创建流程
  if (param.state == State::Create) {
    if (entity == entt::null) {
      entity = reg.create();
      auto fan = qlib::Fan::create();

      reg.emplace<qlib::Fan::s_ptr>(entity, fan);

      // 更新参数
      fan->center = pos;
      fan->radius = 0;

      // 可视化
      add_cache_obj(reg, event_writer, layout_cmd, entity, param, query);
      param.clear_tag = true;
    } else {
      if (param.is_moveing) {
        param.is_moveing = false;
        auto fan = reg.get<qlib::Fan::s_ptr>(entity);

        pos = getNowPoint(query, fan->center);

        auto cha = pos - fan->center;
        double angle = atan2(cha.y, cha.x);

        double r = cha.length();
        fan->radius = r;
        param.have_r = true;

        fan->angle = qlib::Vec2d(angle - 0.0001, angle);

        update_cache_obj(reg, event_writer, layout_cmd, entity, param);
        param.clear_tag = true;
      }
    }
  }

  if (param.state == State::Update) {
    auto& fan_ptr = reg.get<qlib::Fan::s_ptr>(entity);
    qlib::Vec2d last_points = pos;

    auto fan = reg.get<qlib::Fan::s_ptr>(entity);
    pos = getNowPoint(query, fan->center);

    auto cha = pos - fan->center;

    if (!param.have_r) {
      double r = cha.length();
      fan->radius = r;
      double angle = atan2(cha.y, cha.x);

      fan->angle = qlib::Vec2d(angle - 0.0001, angle);
    } else {
      double angle = atan2(cha.y, cha.x);
      fan->angle.y = angle;

      if (fan->angle.y < fan->angle.x) {
        fan->angle.y += 2 * M_PI;
      }
    }

    update_cache_obj(reg, event_writer, layout_cmd, entity, param);
    param.clear_tag = true;
    param.is_moveing = true;
  }

  if (param.state == State::Complete) {
    add_obj(reg, event_writer, layout_cmd, entity, undoRedoModule, cell, param, query, state);

    // undoRedoModule.start(cell);
    // undoRedoModule.add(param.entity);
    // undoRedoModule.end();

    param.reset();
    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  }

  stateTransformEnd(param.state);
}

void Plugin::build(ecs::App& app) {
  app.add_stage<InitStage>();
  app.add_stage<UpdateStage>();

  app.init_event<Event>();

  app.add_systems<InitStage>(init);
  app.add_systems<UpdateStage>(update);
  app.add_systems<ecs::stage::Last>(clear_tag);
}

}  // namespace qbe::draw::fan